package com.ruoyi.recyclecomprehensive.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.recycle.constant.OrderInfoConstant;
import com.ruoyi.recycle.domain.*;
import com.ruoyi.recycle.dto.AttractDataQueryDTO;
import com.ruoyi.recycle.dto.AttractRecordQueryDTO;
import com.ruoyi.recycle.dto.MerchantBillRecordQueryDTO;
import com.ruoyi.recycle.dto.PaymentDTO;
import com.ruoyi.recycle.exception.BusinessException;
import com.ruoyi.recycle.mapper.BillRecordMapper;
import com.ruoyi.recycle.mapper.ClientUserManagementMapper;
import com.ruoyi.recycle.properties.Wxproperties;
import com.ruoyi.recycle.service.*;
import com.ruoyi.recycle.service.impl.WechatPaymentService;
import com.ruoyi.recycle.utils.OrderNoGenerateUtil;
import com.ruoyi.recycle.vo.*;
import com.ruoyi.recyclecomprehensive.dto.WithDrawDTO;
import com.ruoyi.recyclecomprehensive.service.PersonalService;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.faceid.v20180301.FaceidClient;
import com.tencentcloudapi.faceid.v20180301.models.ImageRecognitionRequest;
import com.tencentcloudapi.faceid.v20180301.models.ImageRecognitionResponse;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PersonalServiceImpl implements PersonalService {
    @Autowired
    private OrderNoGenerateUtil orderNoGenerateUtil;
    @Autowired
    private WechatPaymentService paymentService;
    @Autowired
    private IFinanceManagementService financeManagementService;
    @Autowired
    private IIntegralConfigService iIntegralConfigService;
    @Autowired
    private IMerchantManagementService merchantManagementService;
    @Autowired
    private BillRecordService billRecordService;
    @Autowired
    private IShopManagementService shopManagementService;
    @Autowired
    private IRecycleOrderService recycleOrderService;
    @Autowired
    private IRecycleCommodityService recycleCommodityService;
    @Autowired
    private Wxproperties wxproperties;
    @Autowired
    private ExchangeRecordService exchangeRecordService;
    @Autowired
    private IHousekeepingOrderService housekeepingOrderService;
    @Autowired
    private IClientUserManagementService clientUserManagementService;


    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Map<String, String> charge(PaymentDTO paymentDTO, Long userId) {
        try {
            final String chargeOrderNo = orderNoGenerateUtil.getIncr(OrderInfoConstant.CHARGE_ORDER);
            final IntegralConfig integralConfig = iIntegralConfigService.getOne(Wrappers.lambdaQuery(new IntegralConfig())
                    .eq(IntegralConfig::getType, "1"));
            paymentDTO.setOrderNo(chargeOrderNo);
            final BigDecimal blueCoin = paymentDTO.getTotalFee()
                    .multiply(BigDecimal.valueOf(integralConfig.getIntegral()), MathContext.UNLIMITED);
            billRecordService.save(new BillRecord().setIncome(blueCoin)
                    .setOrderNo(chargeOrderNo)
                    .setUserId(userId)
                    .setAccount(paymentDTO.getAccount())
                    .setType(6)
                    .setUserType(2));
            exchangeRecordService.save(new ExchangeRecord()
                    .setAmount(paymentDTO.getTotalFee())
                    .setOrderNo(chargeOrderNo)
                    .setAccount(paymentDTO.getAccount())
                    .setType("充值")
                    .setExchangeStatus("支付中")
                    .setSource("综合站")
                    .setBlueCoin(blueCoin.longValue()));
            return paymentService.pay(paymentDTO.setAppId(wxproperties.getComprehensiveAppId())
                    .setNotifyUrl("https://bluestarhuman.com/recycle/ruoyi-comprehensive-station/personalCenter/payCallBack"));
        } catch (Exception e) {
            final String message = e.getMessage();
            Map<String, String> errorMap = new HashMap<>(2);
            errorMap.put("充值失败", "500");
            errorMap.put("原因", message);
            return errorMap;
        }

    }

    @Override
    public Map<String, String> payCallBack(HttpServletRequest request) {
        final Map<String, String> callBackMap = paymentService.payCallBack(request);
        final String orderNo = callBackMap.get("outTradeNo");
        if (StrUtil.isNotEmpty(orderNo)) {
            final IntegralConfig integralConfig = iIntegralConfigService.getOne(Wrappers.lambdaQuery(new IntegralConfig())
                    .eq(IntegralConfig::getType, "1"));
            final ExchangeRecord exchangeRecord = exchangeRecordService
                    .getById(orderNo);
            final int chargeIntegral = exchangeRecord.getAmount().multiply(BigDecimal
                    .valueOf(integralConfig.getIntegral())).intValueExact();
            if (StrUtil.equals(exchangeRecord.getExchangeStatus(), "已充值")) {
                final MerchantManagement management = merchantManagementService.getOne(Wrappers.lambdaQuery(new MerchantManagement())
                        .eq(MerchantManagement::getMerchantNumber, exchangeRecord.getAccount()));
                management.setIntegral(management.getIntegral() + chargeIntegral);
                merchantManagementService.updateById(management);
            } else {
                log.info("充值订单号为:{}未能完成充值,请检查", orderNo);
            }
            callBackMap.remove("outTradeNo");
        }
        return callBackMap;

    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void withDraw(WithDrawDTO withDrawDTO, Long userId) {
        if (withDrawDTO.getAmount().scale() > 0) {
            throw new BusinessException("请输入整数");
        }
        final IntegralConfig integralConfig = iIntegralConfigService.getOne(Wrappers.lambdaQuery(new IntegralConfig())
                .eq(IntegralConfig::getType, "1"));
        final MerchantManagement management = merchantManagementService.getOne(Wrappers.lambdaQuery(new MerchantManagement()).eq(MerchantManagement::getMerchantNumber, withDrawDTO.getAccount()));
        final BigDecimal integralDV = BigDecimal.valueOf(management.getIntegral());
        final BigDecimal balance = integralDV.subtract(withDrawDTO.getAmount());
        final int compare = balance.compareTo(BigDecimal.ZERO);
        if (compare < 0) {
            throw new BusinessException("提现额度大于账户已有额度,请重新输入");
        } else if (management.getIntegral() == 0) {
            throw new BusinessException("您的账户余额为0");
        }
        merchantManagementService.updateById(management.setIntegral(balance.longValue()));
        final BigDecimal amount = withDrawDTO.getAmount()
                .divide(BigDecimal.valueOf(integralConfig.getIntegral()), MathContext.UNLIMITED);
        String withDrawOrderNo = orderNoGenerateUtil.getIncr(OrderInfoConstant.WITHDRAW_ORDER);
        billRecordService.save(new BillRecord().setOutput(withDrawDTO.getAmount())
                .setOrderNo(withDrawOrderNo).setAccount(withDrawDTO.getAccount()).setUserId(userId)
                .setType(3).setUserType(2));
        exchangeRecordService.save(new ExchangeRecord().setExchangeStatus("待审核")
                .setType("提现")
                .setAccount(withDrawDTO.getAccount())
                .setAmount(amount)
                .setOrderNo(withDrawOrderNo)
                // .setOrderBatchNo(orderNoGenerateUtil.getIncr(OrderInfoConstant.ORDER_BATCH_NO))
                .setSource("综合站")
                .setBlueCoin(withDrawDTO.getAmount().longValue()));
        financeManagementService.save(new FinanceManagement()
                .setCreatedBy(withDrawDTO.getAccount())
                .setOrderNumber(withDrawOrderNo)
                .setPhone(management.getPhone())
                .setStatus("待审核")
                .setUserName(management.getMerchantName())
                .setWithdrawIntegral(withDrawDTO.getAmount().longValue())
                .setWithdrawMoney(amount)
                .setWithdrawType("积分")
                .setCreatedBy(management.getMerchantName())
                .setBankNumber(management.getBankNumber())
                .setBankUserName(management.getBankUserName())
                .setWithdrawTime(new Date()));

    }

    @Override
    public IntegralConfig getIntegralConfigs() {
        return iIntegralConfigService.getOne(Wrappers.lambdaQuery(new IntegralConfig()).eq(IntegralConfig::getType, 1));
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean addShop(ShopManagement shopManagement) {
        if (StrUtil.isEmpty(shopManagement.getHeadPortrait())) {
            shopManagement.setHeadPortrait(wxproperties.getDefaultPortrait());
        }
        shopManagementService.insertShopManagement(shopManagement);
        return true;
    }

    @Override
    public RecycleCategoryVO recycleCategoryStatistics(Long merchantId) {
        final List<RecycleOrder> orders = recycleOrderService.list(Wrappers.lambdaQuery(new RecycleOrder()).eq(RecycleOrder::getMerchantId, merchantId));
        List<RecycleCategoryVO.CategoryVO> categoryVOS = new ArrayList<>();
        RecycleCategoryVO recycleCategoryVO = new RecycleCategoryVO();
        if (CollUtil.isNotEmpty(orders)) {
            final List<String> orderNos = orders.stream().map(RecycleOrder::getRecycleOrderNo).collect(Collectors.toList());
            final LambdaQueryWrapper<RecycleCommodity> queryWrapper = Wrappers.lambdaQuery(new RecycleCommodity()).in(RecycleCommodity::getOrderId, orderNos)
                    .groupBy(RecycleCommodity::getRecycleName);
            categoryVOS = recycleCommodityService.sumWeightByType(queryWrapper);
            final double sumWeight = categoryVOS.stream().map(rv -> rv.getWeight() == null ? rv.setWeight(BigDecimal.ZERO) : rv.setWeight(rv.getWeight()))
                    .mapToDouble(rv -> rv.getWeight().doubleValue()).sum();
            final BigDecimal weightDecimal = BigDecimal.valueOf(sumWeight);
            final BigDecimal ton = weightDecimal.divide(BigDecimal.valueOf(1000), 4);
            recycleCategoryVO.setRecycleCategories(categoryVOS);
            recycleCategoryVO.setIcons(ton).setReduceWeightAmount(weightDecimal);
        }
        return recycleCategoryVO;
    }


    @Override
    @SneakyThrows
    public Boolean certificateIdentify(MultipartFile file, String idCardNo, String name) {
        byte[] buffer = null;
        InputStream inputStream = file.getInputStream();
        try {
            buffer = new byte[inputStream.available()];
            inputStream.read(buffer);
            final String encodeImage = new BASE64Encoder().encode(buffer);
            // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
            Credential cred = new Credential(wxproperties.getCouldSecretId(), wxproperties.getCouldSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("faceid.tencentcloudapi.com");
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            FaceidClient client = new FaceidClient(cred, "", clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            ImageRecognitionRequest req = new ImageRecognitionRequest();
            req.setIdCard(idCardNo);
            req.setImageBase64(encodeImage);
            req.setName(name);
            // 返回的resp是一个ImageRecognitionResponse的实例，与请求对象对应
            ImageRecognitionResponse resp = client.ImageRecognition(req);
            // 输出json格式的字符串回包
            final String respJson = ImageRecognitionResponse.toJsonString(resp);
            final JSONObject jsonObject = JSONObject.parseObject(respJson);
            final String result = jsonObject.getString("Result");
            if (StrUtil.equalsIgnoreCase(result, "Success")) {
                return true;
            }
            log.info("人脸核身认证返回失败,原因:{}", jsonObject.getString("Description"));
            return false;
        } catch (Exception e) {
            log.info("人脸核身认证失败,原因:{}", e.getMessage());
            return false;
        } finally {
            IoUtil.close(inputStream);
        }
    }

    @Override
    public List<ExchangeRecord> queryExchangeRecord(MerchantBillRecordQueryDTO queryDTO) {
        LambdaQueryWrapper<ExchangeRecord> queryWrapper = Wrappers.lambdaQuery(new ExchangeRecord())
                .eq(ExchangeRecord::getAccount, queryDTO.getAccount()).orderByDesc(ExchangeRecord::getCreateTime);
        final String type = queryDTO.getType();
        if (StrUtil.equals(type, "0")) {
            queryWrapper.eq(ExchangeRecord::getType, "充值").eq(ExchangeRecord::getExchangeStatus, "已充值");
        } else {
            queryWrapper.eq(ExchangeRecord::getType, "提现");
        }
        if (queryDTO.getSearchTimeBegin() != null) {
            queryWrapper.ge(ExchangeRecord::getCreateTime, queryDTO.getSearchTimeBegin());
        }
        if (queryDTO.getSearchTimeEnd() != null) {
            queryWrapper.le(ExchangeRecord::getCreateTime, queryDTO.getSearchTimeEnd());
        }
        final List<ExchangeRecord> exchangeRecords = exchangeRecordService.list(queryWrapper);
        if (CollUtil.isNotEmpty(exchangeRecords) && StrUtil.equals(queryDTO.getType(), "3")) {
            final List<String> orderNos = exchangeRecords.stream().map(ExchangeRecord::getOrderNo).collect(Collectors.toList());
            final List<FinanceManagement> financeRecords = financeManagementService.list(Wrappers.lambdaQuery(new FinanceManagement())
                    .in(FinanceManagement::getOrderNumber, orderNos));
            if (CollUtil.isNotEmpty(financeRecords)) {
                exchangeRecords.forEach(r -> {
                    r.setType("3");
                    final FinanceManagement financeRecord = financeRecords.stream().filter(f -> StrUtil.equals(f.getOrderNumber(), r.getOrderNo())).findFirst()
                            .orElse(null);
                    if (Objects.nonNull(financeRecord)) {
                        final String status = financeRecord.getStatus();
                        switch (status) {
                            case "驳回":
                                r.setExchangeStatus("提现失败");
                                break;
                            case "同意":
                                r.setExchangeStatus("已到账");
                                break;
                            default:
                                r.setExchangeStatus("未到账");

                        }
                    }
                });
            }
        } else {
            exchangeRecords.forEach(ex -> {
                ex.setType("0");
            });
        }

        return exchangeRecords;
    }

    @Override
    public BillRecordDetailVO getBillRecordDetail(String billNo) {
        final BillRecord record = billRecordService.getOne(Wrappers.lambdaQuery(new BillRecord()).eq(BillRecord::getOrderNo, billNo));
        final BillRecordDetailVO detailVO = new BillRecordDetailVO();
        BeanUtils.copyProperties(record, detailVO);
        if (StrUtil.startWith(billNo, OrderInfoConstant.RECYCLE_ORDER)) {
            final RecycleOrder recycleOrder = recycleOrderService.getById(billNo);
            detailVO.setRecycleOrder(recycleOrder);
        } else if (StrUtil.startWith(billNo, OrderInfoConstant.WITHDRAW_ORDER)) {
            final FinanceManagement finance = financeManagementService.getOne(Wrappers.lambdaQuery(new FinanceManagement())
                    .eq(FinanceManagement::getOrderNumber, billNo));
            final String status = finance.getStatus();
            switch (status) {
                case "驳回":
                    record.setStatus("提现失败");
                    break;
                case "同意":
                    record.setStatus("已到账");
                    break;
                default:
                    record.setStatus("未到账");

            }
        } else if (StrUtil.startWith(billNo, OrderInfoConstant.HOUSEKEEPING_ORDER)) {
            final HousekeepingOrder housekeepingOrder = housekeepingOrderService.getById(billNo);
            final BigDecimal practicalMoney = housekeepingOrder.getPracticalMoney();
            final IntegralConfig config = iIntegralConfigService
                    .getOne(Wrappers.lambdaQuery(new IntegralConfig()).eq(IntegralConfig::getType, "1"));
            final BigDecimal blueCoin = practicalMoney.multiply(BigDecimal.valueOf(config.getIntegral()), MathContext.UNLIMITED);
            detailVO.setHousekeepingOrder(housekeepingOrder).setIncome(blueCoin);
        }

        return detailVO;
    }

    @Override
    public AttractRecordStatisticsVO attractRecordStatistics(Long merchantId) {
        final List<ShopManagement> shops = shopManagementService.list(Wrappers.lambdaQuery(new ShopManagement())
                .eq(ShopManagement::getMerchantId, merchantId));
        final LambdaQueryWrapper<RecycleOrder> recycleWrapper = Wrappers.lambdaQuery(new RecycleOrder()).eq(RecycleOrder::getMerchantId, merchantId);
        final LambdaQueryWrapper<HousekeepingOrder> houseWrapper = Wrappers.lambdaQuery(new HousekeepingOrder()).eq(HousekeepingOrder::getMerchantId, merchantId);
        final Date date = new Date();
        final String endDate = DateUtil.formatDate(DateUtil.endOfMonth(date).toJdkDate());
        final String beginDate = DateUtil.formatDate(DateUtil.beginOfMonth(date).toJdkDate());
        final int houseOrders = housekeepingOrderService.count(houseWrapper);
        final int recycleOrders = recycleOrderService.count(recycleWrapper);
        final int houseMonths = housekeepingOrderService.count(houseWrapper.between(HousekeepingOrder::getCreatedTime, beginDate, endDate));
        final int recycleMonths = recycleOrderService.count(recycleWrapper.between(RecycleOrder::getCreatedTime, beginDate, endDate));
        int clientCount = 0;
        int clientMonth = 0;
        final boolean notEmpty = CollUtil.isNotEmpty(shops);
        if (notEmpty) {
            final List<Long> shopIds = shops.stream().map(ShopManagement::getId).collect(Collectors.toList());
            final LambdaQueryWrapper<ClientUserManagement> clientWrapper = Wrappers.lambdaQuery(new ClientUserManagement()).in(ClientUserManagement::getShopId, shopIds);
            clientCount = clientUserManagementService.count(clientWrapper);
            clientMonth = clientUserManagementService.count(clientWrapper.between(ClientUserManagement::getCreatedTime, beginDate, endDate));

        }
        return new AttractRecordStatisticsVO()
                .setAttractAmount(clientCount)
                .setAttractAmountMonth(clientMonth)
                .setOrderAmount(houseOrders + recycleOrders)
                .setOrderAmountMonth(houseMonths + recycleMonths)
                .setShopAmount(notEmpty ? shops.size() : 0);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<AttractRecordVO> attractRecordList(AttractRecordQueryDTO queryDTO) {
        LambdaQueryWrapper<ShopManagement> queryWrapper = Wrappers.lambdaQuery(new ShopManagement())
                .eq(ShopManagement::getMerchantId, queryDTO.getMerchantId());
        final List<ShopManagement> shopList = shopManagementService.list(queryWrapper);
        if (CollUtil.isEmpty(shopList)) {
            return new ArrayList<>();
        }
        final Date date = new Date();
        final String today = DateUtil.formatDate(date);
        final String begin = DateUtil.formatDate(DateUtil.beginOfMonth(date));
        final String end = DateUtil.formatDate(DateUtil.endOfMonth(date));
        final List<Long> shopIds = shopList.stream().map(ShopManagement::getId).collect(Collectors.toList());
        List<AttractRecordVO> dailyAttract;
        ClientUserManagementMapper clientMapper = (ClientUserManagementMapper) clientUserManagementService.getBaseMapper();
        LambdaQueryWrapper<ClientUserManagement> attractWrapper = Wrappers.lambdaQuery(new ClientUserManagement());
        boolean notEmptyCollect;
        if (StrUtil.equals(queryDTO.getSearchType(), "达人")) {
            LambdaQueryWrapper<ClientUserManagement> dailyWrapper = initWrapper(shopIds, queryDTO, attractWrapper, "today", today, begin, end);
            dailyAttract = clientMapper.countClientAttract(dailyWrapper);
            dailyWrapper.clear();
            LambdaQueryWrapper<ClientUserManagement> monthlyWrapper = initWrapper(shopIds, queryDTO, attractWrapper, "month", today, begin, end);
            List<AttractRecordVO> monthlyAttract = clientMapper.countClientAttract(monthlyWrapper);
            notEmptyCollect = CollUtil.isNotEmpty(dailyAttract);
            if (notEmptyCollect) {
                if (CollUtil.isNotEmpty(monthlyAttract)) {
                    dailyAttract.forEach(d -> {
                        final AttractRecordVO monthlyData = monthlyAttract.stream().filter(m -> m.getClientId().equals(d.getClientId())).findFirst().get();
                        d.setOrderMonth(monthlyData.getAttractDay());
                        final Long clientId = d.getClientId();
                        int housekeepingCount = housekeepingOrderService.count(Wrappers.lambdaQuery(new HousekeepingOrder())
                                .eq(HousekeepingOrder::getClientId, clientId)
                                .between(HousekeepingOrder::getCreatedTime, begin, end));
                        int recycleOrderCount = recycleOrderService.count(Wrappers.lambdaQuery(new RecycleOrder()).eq(RecycleOrder::getClientId, clientId)
                                .between(RecycleOrder::getCreatedTime, begin, end));
                        d.setOrderMonth(housekeepingCount + recycleOrderCount);
                    });
                }
            }
        } else {
            LambdaQueryWrapper<ClientUserManagement> dailyWrapper = initWrapper(shopIds, queryDTO, attractWrapper, "today", today, begin, end);
            dailyAttract = clientMapper.countShopAttract(dailyWrapper);
            dailyWrapper.clear();
            LambdaQueryWrapper<ClientUserManagement> monthlyWrapper = initWrapper(shopIds, queryDTO, attractWrapper, "month", today, begin, end);
            List<AttractRecordVO> monthlyAttract = clientMapper.countShopAttract(monthlyWrapper);
            notEmptyCollect = CollUtil.isNotEmpty(dailyAttract);
            if (notEmptyCollect) {
                if (CollUtil.isNotEmpty(monthlyAttract)) {
                    dailyAttract.forEach(d -> {
                        final AttractRecordVO monthlyData = monthlyAttract.stream().filter(m -> m.getClientId().equals(d.getClientId())).findFirst().get();
                        d.setOrderMonth(monthlyData.getAttractDay());
                        final Long shopId = d.getShopId();
                        final ShopAttractVO clientVOS = clientMapper.groupClientByShop(shopId);
                        if (Objects.nonNull(clientVOS)) {
                            final List<Long> clientIds = clientVOS.getClientIds();
                            final int housekeepingCount = housekeepingOrderService.count(Wrappers.lambdaQuery(new HousekeepingOrder())
                                    .in(HousekeepingOrder::getClientId, clientIds)
                                    .between(HousekeepingOrder::getCreatedTime, begin, end));
                            final int recycleOrderCount = recycleOrderService.count(Wrappers.lambdaQuery(new RecycleOrder()).in(RecycleOrder::getClientId, clientIds)
                                    .between(RecycleOrder::getCreatedTime, begin, end));
                            d.setOrderMonth(housekeepingCount + recycleOrderCount);
                        } else {
                            d.setOrderMonth(0);
                        }

                    });
                }
            }

        }

        if (queryDTO.getMaxAttractDay() && notEmptyCollect) {
            final AttractRecordVO dailyMax = dailyAttract.stream().max(Comparator.comparing(AttractRecordVO::getAttractDay, Integer::compareTo)).get();
            dailyAttract.clear();
            dailyAttract.add(dailyMax);
        } else if (queryDTO.getMaxAttractMonth() && notEmptyCollect) {
            final AttractRecordVO monthlyMax = dailyAttract.stream().max(Comparator.comparing(AttractRecordVO::getAttractMonth, Integer::compareTo)).get();
            dailyAttract.clear();
            dailyAttract.add(monthlyMax);
        }
        return dailyAttract;
    }

    @Override
    public AttractRecordStatisticsSingle attractRecordStatisticsSingle(Long shopId, Long clientId) {
        AttractRecordStatisticsSingle single = new AttractRecordStatisticsSingle();
        final ClientUserManagement client = new ClientUserManagement();
        final HousekeepingOrder housekeepingOrder = new HousekeepingOrder();
        final RecycleOrder recycleOrder = new RecycleOrder();
        final BillRecordMapper billMapper = (BillRecordMapper) billRecordService.getBaseMapper();
        final BillRecord billRecord = new BillRecord();
        Integer[] types = {1, 2};
        if (Objects.nonNull(shopId)) {
            final List<ClientUserManagement> attractList = clientUserManagementService.list(Wrappers.lambdaQuery(client)
                    .eq(ClientUserManagement::getShopId, shopId));
            if (CollUtil.isNotEmpty(attractList)) {
                final List<Long> clientIds = attractList.stream().map(ClientUserManagement::getId).collect(Collectors.toList());
                final int houseOrders = housekeepingOrderService.count(Wrappers.lambdaQuery(housekeepingOrder)
                        .in(HousekeepingOrder::getClientId, clientIds));
                final int recycleOrderCount = recycleOrderService.count(Wrappers.lambdaQuery(recycleOrder).in(RecycleOrder::getClientId, clientIds));
                final BigDecimal sumPercentage = billMapper.sumPercentage(Wrappers.lambdaQuery(billRecord).eq(BillRecord::getUserType, 3)
                        .eq(BillRecord::getUserId, shopId).in(BillRecord::getType, types));
                single.setShopAttractAmount(clientIds.size()).setShopOrderAmount(recycleOrderCount + houseOrders).setPercentage(sumPercentage);
            }

        } else {
            final int attractCount = clientUserManagementService.count(Wrappers.lambdaQuery(client)
                    .eq(ClientUserManagement::getSuperiorId, clientId));
            final int houseCount = housekeepingOrderService.count(Wrappers.lambdaQuery(housekeepingOrder).eq(HousekeepingOrder::getClientId, clientId));
            final int recycleCount = recycleOrderService.count(Wrappers.lambdaQuery(recycleOrder).eq(RecycleOrder::getClientId, clientId));
            BigDecimal sumPercentage = billMapper.sumPercentage(Wrappers.lambdaQuery(billRecord).eq(BillRecord::getUserType, 1).eq(BillRecord::getUserId, shopId).in(BillRecord::getType, types));
            single.setClientAttractAmount(attractCount).setClientOrderAmount(houseCount + recycleCount).setPercentage(sumPercentage);
        }
        return single;
    }

    @Override
    public List<AttractDataVO> singleDataStatistics(AttractDataQueryDTO dataQueryDTO) {
        final Long shopId = dataQueryDTO.getShopId();
        final Long clientId = dataQueryDTO.getClientId();
        ClientUserManagement client = new ClientUserManagement();
        final Date begin = dataQueryDTO.getSearchTimeBegin();
        final Date end = dataQueryDTO.getSearchTimeEnd();
        final BigDecimal zero = BigDecimal.ZERO;
        final ClientUserManagementMapper clientMapper = (ClientUserManagementMapper) clientUserManagementService.getBaseMapper();
        final BillRecordMapper billMapper = (BillRecordMapper) billRecordService.getBaseMapper();
        final BillRecord billRecord = new BillRecord();
        final RecycleOrder recycleOrder = new RecycleOrder();
        final HousekeepingOrder housekeepingOrder = new HousekeepingOrder();
        final Boolean isMonth = dataQueryDTO.getIsMonth();
        final LambdaQueryWrapper<BillRecord> billWrapper = Wrappers.lambdaQuery(billRecord);
        final List<AttractDataVO> attractData;
        LambdaQueryWrapper<ClientUserManagement> queryWrapper = Wrappers.lambdaQuery(client);
        if (Objects.nonNull(shopId)) {
            final ShopManagement shop = shopManagementService.getById(shopId);
            final Long salesmanId = shop.getSalesmanId();
            queryWrapper.eq(ClientUserManagement::getShopId, shopId);
            if (Objects.nonNull(begin)) {
                queryWrapper.ge(ClientUserManagement::getCreatedTime, begin);
            } else if (Objects.nonNull(end)) {
                queryWrapper.le(ClientUserManagement::getCreatedTime, end);
            }
            final List<ClientUserManagement> attractList = clientUserManagementService.list(queryWrapper);
            final List<Long> clientIds = attractList.stream().map(ClientUserManagement::getId).collect(Collectors.toList());
            if (isMonth) {
                attractData = clientMapper.shopAttractGroupByMonth(clientIds);
            } else {
                attractData = clientMapper.shopAttractGroupByDay(clientIds);
            }
            if (CollUtil.isNotEmpty(attractData)) {
                attractData.forEach(a -> {
                    final String date = a.getDate();
                    final int recycleCount = recycleOrderService.count(Wrappers.lambdaQuery(recycleOrder)
                            .in(RecycleOrder::getClientId, clientIds)
                            .like(RecycleOrder::getCreatedTime, date));
                    final int houseCount = housekeepingOrderService.count(Wrappers.lambdaQuery(housekeepingOrder)
                            .in(HousekeepingOrder::getClientId, clientIds)
                            .like(HousekeepingOrder::getCreatedTime, date));
                    initBillRecordWrapper(billWrapper, isMonth);
                    final BigDecimal shopSumPercentage = billMapper.sumPercentage(billWrapper.eq(BillRecord::getUserType, 3)
                            .eq(BillRecord::getUserId, shopId).like(BillRecord::getCreateTime, date));
                    billWrapper.clear();
                    initBillRecordWrapper(billWrapper, isMonth);
                    final BigDecimal salesmanSumPercentage = billMapper.sumPercentage(billWrapper.eq(BillRecord::getUserType, 4)
                            .eq(BillRecord::getUserId, salesmanId).like(BillRecord::getCreateTime, date));
                    billWrapper.clear();
                    BigDecimal recycleFinishedOrders = recycleOrderService.sumFinishedOrder(Wrappers.lambdaQuery(recycleOrder).in(RecycleOrder::getClientId, clientIds)
                            .like(RecycleOrder::getCreatedTime, date).isNotNull(RecycleOrder::getIntegral).eq(RecycleOrder::getStatus, "6"));
                    BigDecimal houseFinishedOrders = housekeepingOrderService.sumFinishedOrder(Wrappers.lambdaQuery(housekeepingOrder).in(HousekeepingOrder::getClientId, clientIds)
                            .like(HousekeepingOrder::getCreatedTime, date).eq(HousekeepingOrder::getStatus, "5"));
                    BigDecimal recycleSum = Objects.isNull(recycleFinishedOrders) ? BigDecimal.ZERO : recycleFinishedOrders;
                    BigDecimal houseSum = Objects.isNull(houseFinishedOrders) ? BigDecimal.ZERO : houseFinishedOrders;
                    final BigDecimal finishedSum = houseSum.add(recycleSum);
                    a.setOrderCount(houseCount + recycleCount)
                            .setShopDrawPercentage(Objects.isNull(shopSumPercentage) ? zero : shopSumPercentage)
                            .setSalesmanDrawPercentage(salesmanSumPercentage).setOrderSum(finishedSum);

                });
            }
        } else {
            queryWrapper.eq(ClientUserManagement::getSuperiorId, clientId);
            if (Objects.nonNull(begin)) {
                queryWrapper.ge(ClientUserManagement::getCreatedTime, begin);
            } else if (Objects.nonNull(end)) {
                queryWrapper.le(ClientUserManagement::getCreatedTime, end);
            }
            queryWrapper.last("GROUP BY date ORDER BY date DESC");
            if (isMonth) {
                attractData = clientMapper.clientAttractGroupByMonth(queryWrapper);
            } else {
                attractData = clientMapper.clientAttractGroupByDay(queryWrapper);
            }
            if (CollUtil.isNotEmpty(attractData)) {
                final ClientUserManagement user = clientUserManagementService.getById(clientId);
                final Long salesmanId = user.getSalesmanId();
                BigDecimal salesmanSumPercentage = BigDecimal.ZERO;
                for (AttractDataVO a : attractData) {
                    final String date = a.getDate();
                    final int recycleCount = recycleOrderService.count(Wrappers.lambdaQuery(recycleOrder)
                            .eq(RecycleOrder::getClientId, clientId)
                            .like(RecycleOrder::getCreatedTime, date));
                    final int houseCount = housekeepingOrderService.count(Wrappers.lambdaQuery(housekeepingOrder)
                            .eq(HousekeepingOrder::getClientId, clientId)
                            .like(HousekeepingOrder::getCreatedTime, date));
                    initBillRecordWrapper(billWrapper, isMonth);
                    final BigDecimal clientSumPercentage = billMapper.sumPercentage(billWrapper.eq(BillRecord::getUserType, 1)
                            .eq(BillRecord::getUserId, clientId).like(BillRecord::getCreateTime, date));
                    billWrapper.clear();
                    if (Objects.nonNull(salesmanId)) {
                        initBillRecordWrapper(billWrapper, isMonth);
                        salesmanSumPercentage = billMapper.sumPercentage(billWrapper.eq(BillRecord::getUserType, 4)
                                .eq(BillRecord::getUserId, salesmanId).like(BillRecord::getCreateTime, date));
                        billWrapper.clear();
                    }
                    final BigDecimal recycleFinishedOrders = recycleOrderService.sumFinishedOrder(Wrappers.lambdaQuery(recycleOrder).eq(RecycleOrder::getClientId, clientId)
                            .like(RecycleOrder::getCreatedTime, date).isNotNull(RecycleOrder::getIntegral).eq(RecycleOrder::getStatus, "6"));
                    final BigDecimal houseFinishedOrders = housekeepingOrderService.sumFinishedOrder(Wrappers.lambdaQuery(housekeepingOrder).eq(HousekeepingOrder::getClientId, clientId)
                            .like(HousekeepingOrder::getCreatedTime, date).eq(HousekeepingOrder::getStatus, "5"));
                    BigDecimal recycleSum = Objects.isNull(recycleFinishedOrders) ? BigDecimal.ZERO : recycleFinishedOrders;
                    BigDecimal houseSum = Objects.isNull(houseFinishedOrders) ? BigDecimal.ZERO : houseFinishedOrders;
                    final BigDecimal clientFinishedSum = houseSum.add(recycleSum);
                    a.setOrderCount(houseCount + recycleCount)
                            .setClientDrawPercentage(Objects.isNull(clientSumPercentage) ? zero : clientSumPercentage)
                            .setSalesmanDrawPercentage(Objects.isNull(salesmanSumPercentage) ? zero : salesmanSumPercentage).setOrderSum(clientFinishedSum);

                }
            }
        }
        return attractData;
    }


    private void initBillRecordWrapper(LambdaQueryWrapper<BillRecord> billWrapper, Boolean isMonth) {
        Integer[] types = {1, 2};
        billWrapper.in(BillRecord::getType, types);
        if (isMonth) {
            billWrapper.last("GROUP BY DATE_FORMAT(create_time,'%Y-%m')");
        } else {
            billWrapper.last("GROUP BY DATE_FORMAT(create_time,'%Y-%m-%d')");
        }
    }

    private LambdaQueryWrapper<ClientUserManagement> initWrapper(List<Long> shopIds, AttractRecordQueryDTO queryDTO, LambdaQueryWrapper<ClientUserManagement> queryWrapper,
                                                                 String period, String today, String begin, String end) {

        queryWrapper.in(ClientUserManagement::getShopId, shopIds);
        if (StrUtil.equals(queryDTO.getSearchType(), "达人")) {
            queryWrapper.isNotNull(ClientUserManagement::getSuperiorId).groupBy(ClientUserManagement::getSuperiorId);
        } else {
            queryWrapper.groupBy(ClientUserManagement::getShopId);
        }
        if (Objects.nonNull(queryDTO.getSalesmanId())) {
            queryWrapper.eq(ClientUserManagement::getSalesmanId, queryDTO.getSalesmanId());
        }
        if (Objects.nonNull(queryDTO.getSearchTimeEnd())) {
            queryWrapper.le(ClientUserManagement::getCreatedTime, queryDTO.getSearchTimeEnd());
        }
        if (Objects.nonNull(queryDTO.getSearchTimeBegin())) {
            queryWrapper.ge(ClientUserManagement::getCreatedTime, queryDTO.getSearchTimeBegin());
        }
        if (StrUtil.equals(period, "today")) {
            queryWrapper.like(ClientUserManagement::getCreatedTime, today);
        } else if (StrUtil.equals(period, "month")) {
            queryWrapper.between(ClientUserManagement::getCreatedTime, begin, end);
        }
        return queryWrapper;
    }

}
